import { _decorator, Node, Vec3 } from 'cc';
import { BallGameBase } from './BallGameBase';
import { BallAttribute, BallColor } from '../core/BallAttribute';
import { Game, HitBallAttribute } from '../core/Game';
import { PlayUser } from '../core/PlayUser';
import { EventManager } from '../core/EventManager';
export class SnookerBallGame extends BallGameBase {
  constructor(node: Node) {
    super(node);
  }
  public initBallsPosition() {
    const ballsNode = this.billiamNode.getChildByName('Balls');
    ballsNode.active = false;
    // 初始化球的位置
    const snookerNode = this.billiamNode.getChildByName('SnookerBalls');

    snookerNode.active = true;
    const balls = snookerNode.children;
    for (const ball of balls) {
      const pt = BallAttribute.getSnookerPointByName(ball.name);
      EventManager.Instance().Emit('InitBallPosition', {
        ballName: ball.name, pos: new Vec3(pt.x, pt.y, pt.z),
      });
    }

    // 设置白球的位置
    EventManager.Instance().Emit('InitMainBallPosition', new Vec3(12, 0, -3));
  }

  // 游戏是否已经结束
  public checkGameEnd() {
    // TODO: 超分可以提前判断，但是还是让用户操作认输更好
    const balls = this.getActiveBalls();
    
    if (balls.length !== 0) return false;
    const csc = Game.Instance().playUsers[0].score;
    const osc = Game.Instance().playUsers[1].score;
    // 打完了，但是平分，需要进入抢黑大战
    if (csc === osc) {
      return false;
    }
    return true;
  }
  // 是否进球得分
  public hasHoledScore(hitBallList: Array<HitBallAttribute>, step: number, color: BallColor) {
    // 斯诺克红球打完，彩球按照序号打
    if (color.isSpecialColor()) {
      const balls = this.getActiveBalls();
      var minIndex = 1000001;
      for (const b of balls) {
        const ba = BallAttribute.getBallByName(b.name);
        if (minIndex < ba.index) {
          minIndex = ba.index;
        }
      }
      for (var i=hitBallList.length-1; i>=0; i--) {
        if (hitBallList[i].step === step) {
          if (hitBallList[i].ba.isMainWhiteBall()) continue;
          if (hitBallList[i].ba.index < minIndex) {
            return true;
          }
        } else {
          break;
        }
      }
    }
    for (var i=hitBallList.length-1; i>=0; i--) {
      if (hitBallList[i].step === step) {
        if (hitBallList[i].ba.isMainWhiteBall()) continue;
        if (hitBallList[i].ba.color === color.color) {
          return true;
        }
      } else {
        break;
      }
    }
    return false;
  }
  public isIllegalHitBall(firstCollideBall: BallAttribute, hitBallList: Array<HitBallAttribute>, step: number, color: BallColor) {
    const res = super.illeageHitBallResult(firstCollideBall, hitBallList, step, color);
    if (res.isIlleagel) return res;
    if (color.isSpecialColor()) { // 特殊花色，进最小的球
      const minBallIndex = this.minHitBallIndex(this.getActiveBalls());
      if (firstCollideBall && firstCollideBall.index <= minBallIndex) {
        return res;
      } else {
        return { isIlleagel: true, message: '未先击中目标球，违规击球' };
      }
    } else { // 同时打进两种颜色的球
      for (var i = hitBallList.length -1; i>=0; i--) {
        const hba = hitBallList[i];
        if (hba.step === step) {
          if (hba.ba.isMainWhiteBall()) {
            continue;
          }
          if (!color.isSameColor(hba.ba.color)) {
            return { isIlleagel: true, message: '打进其他颜色的球' };
          }
        } else {
          break;
        }
      }
    }
    return res;
  }
  // 球桌上当前活跃的球
  public getActiveBalls() {
    const bList = [];
    const balls = this.billiamNode.getChildByName('SnookerBalls').children;
    for (const b of balls) {
      if (b.active) {
        bList.push(b);
      }
    }
    return bList;
  }

  // 当前击球 和受保护 的球列表
  public getHitProtectBalls(color: BallColor) {
    const hitBalls = [];
    const protectBalls = [];
    const balls = this.getActiveBalls();
    // 那么应该击打桌面最小标号的球
    if (color.isSpecialColor()) {
      var minBall = null;
      var minIndex = 1000001;
      for (const b of balls) {
        const ba = BallAttribute.getBallByName(b.name);
        if (ba.index <= minIndex) {
          minIndex = ba.index;
          minBall = b;
        }
      }
      hitBalls.push(minBall);
      for (const b of balls) {
        const ba = BallAttribute.getBallByName(b.name);
        if (ba.index !== minIndex) {
          protectBalls.push(b);
        }
      }
      return { hitBalls, protectBalls };
    }
    for (const b of balls) {
      const ba = BallAttribute.getBallByName(b.name);
      if (color.isSameColor(ba.color)) {
        hitBalls.push(b);
      } else {
        protectBalls.push(b);
      }
    }
    return { hitBalls, protectBalls };
  }

  public getCurrentStepScore(hitBallList: Array<HitBallAttribute>, step: number, color: BallColor) {
    if (color.isRedColorBall()) return 1;
    var maxScore = 0;
    const balls = hitBallList;
    for (var i=balls.length-1; i>=0; i--) {
      if (balls[i].step === step) {
        if (balls[i].ba.isMainWhiteBall()) continue;
        if (balls[i].ba.isColoredColorBall()) {
          if (balls[i].ba.score > maxScore) {
            maxScore = balls[i].ba.score;
          }
        }
      } else {
        break;
      }
    }
    return maxScore;
  }
  public penalyScore() {
    const hitBallList = Game.Instance().hitBallList;
    const step = Game.Instance().currentStep;
    var maxScore = 4;
    for (var i = hitBallList.length -1; i>=0; i--) {
      const hba = hitBallList[i];
      if (hba.step === step) {
        if (hba.ba.isMainWhiteBall()) {
          continue;
        }
        if (hba.ba.score > maxScore) {
          maxScore = hba.ba.score;
        }
      } else {
        break;
      }
    }
    return maxScore;
  }
  public getUserHitColorText(color: BallColor) {
    if (!color.isSpecialColor()) {
      return color.getColorText();
    }
    const balls = this.getActiveBalls();
    var minBall = null;
    var minIndex = 1000001;
    for (const b of balls) {
      const ba = BallAttribute.getBallByName(b.name);
      if (ba.index <= minIndex) {
        minIndex = ba.index;
        minBall = b;
      }
    }
    if (minBall) {
      return BallAttribute.getChineseName(minBall.name);
    }
    return '最小彩色球';
  }
  public swapCurrentUserColor(hasExchangeUser: boolean) {
    const side = Game.Instance().side;
    const playUser = Game.Instance().playUsers[side];
    if (hasExchangeUser) {
      // 斯诺克先击红球
      playUser.color.initRedColor();
    } else {
      playUser.color.swapColor();
    }
    this.changeUserHitBallColor(side);
    this.changeUserHitBallColor(1 - side);
  }

  public isCurrentUserWin(side: number, isIlleagel: boolean) {
    const csc = Game.Instance().playUsers[side].score;
    const osc = Game.Instance().playUsers[1 - side].score;
    return csc > osc;
  }
  public checkOutHoleBalls(isIgnoreColorStage: boolean, isIllegalHitBall: boolean, currentHitBalls: Array<HitBallAttribute>) {
    const actBalls = this.getActiveBalls();
    var minIndex = this.minHitBallIndex(actBalls);
    for (const ball of currentHitBalls) {
      if (ball.ba.index < minIndex) {
        minIndex = ball.ba.index;
      }
    }
    for (const ball of currentHitBalls) {
      if (!ball.ba.isColoredColorBall()) {
        continue;
      }
      if (!isIgnoreColorStage) {
        const ballName = ball.ba.ballName();
        EventManager.Instance().Emit("ResetBallPosition", {
          ballName, pos: BallAttribute.getSnookerPointByName(ballName)
        });
      } else { // 斯诺克最后打菜球阶段
        // 违规击球了，则拿出来
        if (isIllegalHitBall) {
          const ballName = ball.ba.ballName();
          EventManager.Instance().Emit("ResetBallPosition", {
            ballName, pos: BallAttribute.getSnookerPointByName(ballName)
          });
        } else {
          // 打进了非最小球，需要拿出来
          if (ball.ba.index > minIndex) {
            const ballName = ball.ba.ballName();
            EventManager.Instance().Emit("ResetBallPosition", {
              ballName, pos: BallAttribute.getSnookerPointByName(ballName)
            });
            continue;
          }
          // 所有球都打进了，则进行抢黑大战，且分数一致，则进入抢黑大战
          if (Game.Instance().playUsers[0].score === Game.Instance().playUsers[1].score) {
            const ballName = BallAttribute.snookerBlackBallName();
            if (actBalls.length === 0) {
              EventManager.Instance().Emit("ResetBallPosition", {
                ballName, pos: BallAttribute.getSnookerPointByName(ballName)
              });
            }
          }
        }
      }
    }
  }

  public isExcellentLevel(hitBallList: Array<HitBallAttribute>, step: number, color: BallColor, userId: string) {
    return 0;
  }
  // 所有球的信息
  public getAllBallList() {
    const mainBall = this.billiamNode.getChildByName('MainBall').getChildByName('WhiteBall').getChildByName('BallSphereMain');
    const balls = this.billiamNode.getChildByName('SnookerBalls').children;
    return this.getNetFrameBallList(mainBall, balls);
  }
  public isTargetHitBall(color: BallColor, name: string) {
    if (color.isSpecialColor()) {
      const minBall = this.minHitBallAttribute(this.getActiveBalls());
      const ba = BallAttribute.getBallByName(name);
      return minBall.index === ba.index;
    }
    const ba = BallAttribute.getBallByName(name);
    return color.isSameColor(ba.color);
  }
  private minHitBallAttribute(balls: Node[]) {
    var minBall = null;
    var minIndex = 1000001;
    for (const b of balls) {
      const ba = BallAttribute.getBallByName(b.name);
      if (ba.index <= minIndex) {
        minIndex = ba.index;
        minBall = ba;
      }
    }
    return minBall;
  }
  private minHitBallIndex(balls: Node[]) {
    var minIndex = 1000001;
    for (const b of balls) {
      const ba = BallAttribute.getBallByName(b.name);
      if (ba.index <= minIndex) {
        minIndex = ba.index;
      }
    }
    return minIndex;
  }
  // 所有球节点信息
  public getAllBallNodeList() {
    const bList: Array<Node> = [];
    const mainBall = this.billiamNode.getChildByName('MainBall').getChildByName('WhiteBall').getChildByName('BallSphereMain');
    bList.push(mainBall);
    const balls = this.billiamNode.getChildByName('SnookerBalls').children;
    bList.push(...balls);
    return bList;
  }

  public robotRenShu(playUsers: PlayUser[]) {
    if (playUsers.length < 2) {
      return false;
    }
    const balls = this.getActiveBalls();
    // 只剩下一个球，对手超过10分
    if (balls.length <= 1  && playUsers[1].score + 20 < playUsers[0].score) {
      return true;
    }
    // 被对手超过30分
    if (balls.length <= 6 && playUsers[1].score + 40 < playUsers[0].score) {
      return true;
    }
    // 被对手超过40分
    if (balls.length <= 10 && playUsers[1].score + 50 < playUsers[0].score) {
      return true;
    }
    // 被对手超过60分，直接认输
    if (playUsers[1].score + 70 < playUsers[0].score) {
      return true;
    }
    return false;
  }

  private changeUserHitBallColor(side: number) {
    const playUser = Game.Instance().playUsers[side];
    // 打红球时，没有红球了，那么当前用户就用特殊球颜色代替
    if (playUser.color.isRedColorBall()) {
      const balls = this.getActiveBalls();
      for (const b of balls) {
        const ba = BallAttribute.getBallByName(b.name);
        if (ba.isRedColorBall()) {
          return ;
        }
      }
      playUser.color.initSpecialColor();
    }
  }
}